import { AfterViewInit, Component, ElementRef, EventEmitter, Injector, Input, OnChanges, OnInit, Output, SimpleChanges, TemplateRef, ViewChild } from '@angular/core';
import { NotifyService } from '@farris/ui-notify';
import { RowNode, TreeNode, TreeTableComponent } from '@farris/ui-treetable';
import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { IdeTreeToolbarComponent } from './tool-bar/ide-tree-toolbar.component';

export type EnableNodeName = boolean | ((node: TreeNode) => boolean);

@Component({
    selector: 'ide-tree',
    templateUrl: 'ide-tree.component.html',
    styleUrls: ['ide-tree.component.css']
})
export class IdeTreeComponent implements OnInit, AfterViewInit, OnChanges {
    @Input() data: TreeNode[];
    @Input() showLines = false;
    @Input() showLinesOnHover = false;
    @Input() idField = 'id';
    @Input() textField = 'name';
    @Input() labelField = '';
    @Input() showCheckbox = false;
    @Input() virtualized = false;
    @Input() iconCls = '';
    @Input() iconField = '';
    @Input() whenDataIconEmptyUseDefault = false;
    @Input() indentSpacing = 16;

    @Input() textWithId = false;

    @Input() enableToolbar = true;

    @Input() editable: EnableNodeName = false;
    @Input() useIconFromData = true;
    @Input() leafIcon: string;
    @Input() expandIcon: string;
    @Input() collapseIcon: string;

    @Input() enableContextMenu = false;
    @Input() contextMenus = null;
    @Input() beforeShowContextMenu: (e: { [key: string]: any }) => Observable<{ show: boolean, menus: Array<any> }>;


    @Input() selectValue: string;
    @Input() isFormControlTree = false;
    @Input() enableRefresh = false;
    @Input() rowCls;

    @Output() nameChanged = new EventEmitter();
    @Output() refresh = new EventEmitter();
    @Output() selectChanged = new EventEmitter();
    @Output() selectValueChange = new EventEmitter();
    @Output() nodeExpanded = new EventEmitter();
    @Output() nodeExpandedAll = new EventEmitter();
    @Output() nodeCollapsedAll = new EventEmitter();



    @ViewChild('tt') tt: TreeTableComponent;
    @ViewChild('toolbar') tb: IdeTreeToolbarComponent;
    @ViewChild('nodeText') nodeTextTemp: TemplateRef<any>;
    @ViewChild('hiddenInput') hiddenInput: ElementRef;

    loadSuccess = new Subject();

    cols = [];

    activeEditInfo: {
        id: string,
        editing: boolean,
        oldValue?: string,
        value?: string
    } = {
            id: '',
            editing: false,
            oldValue: undefined
        };

    isEditing = false;

    private notifySer: NotifyService;
    constructor(private el: ElementRef, private injector: Injector) {
        this.notifySer = this.injector.get(NotifyService);
    }

    ngOnInit() {
        if (this.useIconFromData) {
            this.checkData(this.data);
        }
        if (!this.labelField) {
            this.labelField = this.idField;
        }

        this.cols = [
            { field: this.textField, title: '', visible: true, width: 100, template: this.nodeTextTemp, styler: this.rowCls }
        ];
    }

    ngAfterViewInit(): void {
        if (this.enableToolbar && this.tb) {
            // 搜索后事件
            this.tb.textChange.pipe(
                debounceTime(300),
                distinctUntilChanged(),
            ).subscribe((e: any) => {

                this.tt.searchHandle.search(this.textField + ',' + this.labelField, e.val);
                const tbody = this.tt.el.nativeElement.querySelector('tbody.farris-treetable-tbody');
                if (tbody) {
                    this.loadSuccess.next({ tt: this.tt, tbody });
                }
            });
        }

        this.tt.loadedData.asObservable().pipe(
            debounceTime(200)
        ).subscribe(() => {
            const tbody = this.tt.el.nativeElement.querySelector('tbody.farris-treetable-tbody');
            if (tbody) {
                this.loadSuccess.next({ tt: this.tt, tbody });
            }
        });
    }

    ngOnChanges(changes: SimpleChanges) {
        if (changes.selectValue && !changes.selectValue.isFirstChange()) {
            this.tt.selectNode(changes.selectValue.currentValue, false);
        }

        if (changes.data && !changes.data.isFirstChange()) {
            if (this.useIconFromData) {
                this.checkData(this.data);
            }
        }
        // if (this.rowCls) {
        //     this.cols = [
        //         { field: this.textField, title: '', visible: true, width: 100, template: this.nodeTextTemp, styler: this.rowCls }
        //     ];
        // }

    }

    private checkData(data: TreeNode[]) {
        if (data && data.length) {
            data.forEach((n: TreeNode) => {
                if (!n[this.iconField]) {
                    n.showIcon = false;
                }
                this.checkData(n.children);
            });
        }
    }

    private isNodeCanEdit(node: TreeNode) {
        if (typeof this.editable === 'boolean') {
            return this.editable;
        }

        if (typeof this.editable === 'function') {
            return this.editable(node);
        }

        return false;
    }

    onMenuItemClick($event: any) {
        const { event, action } = $event;
        switch (action.key) {
            case 'SHOWID':
                this.textWithId = action.value;
                this.tt.detectChanges();
                break;
            case 'EXPANDALL':
                if (!this.isFormControlTree) {
                    this.tt.expandAll();
                }

                this.onNodeExpaned(null);
                this.onNodeExpanedAll();
                break;
            case 'COLLAPSEALL':
                if (!this.isFormControlTree) {
                    this.tt.collapseAll();
                }
                this.onNodeCollapsedAll();
                break;
        }
    }

    // onNodeDblClick($event) {
    // }

    onNodeTextClick($event) {
        const { data, el } = $event;
        const id = data.rowNode.id;

        if (id === this.activeEditInfo.id && this.tt.selectedRow && this.tt.selectedRow.id === id) {
            const val = data.rowData[this.textField];
            this.editNode(val, el);
        }
    }

    onSelectNodeChange($event) {
        this.selectValue = $event.node.id;
        this.selectValueChange.emit($event.node.id);
        this.selectChanged.emit($event);
    }

    // 节点点击事件
    onNodeClick($event: any) {
        if (this.tt.selectedRow && this.tt.selectedRow.id === $event.node.id) {
            this.activeEditInfo.id = $event.node.id;
        } else {
            if (this.activeEditInfo.editing) {
                const { id, value, oldValue } = this.activeEditInfo;
                if (value !== oldValue) {
                    this.tt.update(id, { [this.textField]: value });
                    this.nameChanged.emit({ id, value, tt: this.tt, instance: this });
                }
            }
            this.activeEditInfo.id = '';
        }

        this.stopEditing();
    }

    onKeyDown($event) {
        const key = $event.key;
        if (key === 'F2' && this.tt.selectedRow) {
            const val = this.tt.selectedRow.data[this.textField];
            this.editNode(val, $event.target);
        }
    }

    onNameModelChange($event) {
        this.activeEditInfo.value = $event;
    }

    onNodeNameKeydown($event, oldVal) {
        $event.stopPropagation();

        if ($event.key === 'Enter') {
            const newVal = $event.target.value;
            if (this.activeEditInfo.oldValue !== newVal) {
                this.tt.update(this.tt.selectedRow.id, { [this.textField]: newVal });
                this.nameChanged.emit({ value: newVal, id: this.tt.selectedRow.id });
            }

            this.stopEditing();
        }

        if ($event.key === 'Escape') {
            this.tt.update(this.tt.selectedRow.id, { [this.textField]: this.activeEditInfo.oldValue });
            this.stopEditing();
        }
    }

    private stopEditing() {
        this.activeEditInfo.editing = false;
        this.activeEditInfo.oldValue = undefined;
        this.activeEditInfo.value = undefined;
        this.isEditing = false;
        this.tt.detectChanges();
    }

    editNode(val: string, el?: HTMLElement) {

        const canEdit = this.isNodeCanEdit(this.tt.selectedRow);
        if (!canEdit) {
            return;
        }

        this.activeEditInfo = {
            id: this.tt.selectedRow.id,
            editing: true,
            value: val,
            oldValue: val
        };

        this.tt.detectChanges();

        if (el) {
            setTimeout(() => {
                el.querySelector('input').focus();
                this.isEditing = true;
            }, 10);
        }
    }

    onRefresh($event) {
        this.refresh.emit({ event: $event, tt: this.tt, instance: this });
    }

    getNodeDoms() {
        return this.tt.el.nativeElement.querySelectorAll('tr');
    }

    copyLabel(t: RowNode) {
        if (!this.hiddenInput) {
            return;
        }
        this.hiddenInput.nativeElement.focus();
        this.hiddenInput.nativeElement.value = t.node.data[this.labelField];
        this.hiddenInput.nativeElement['select']();
        document.execCommand('Copy');
        this.hiddenInput.nativeElement.value = '';

        if (this.notifySer) {
            this.notifySer.success('复制成功。');
        } else {
            alert('复制成功。');
        }
    }

    onNodeExpaned($event) {
        const tb = this.tt.el.nativeElement.querySelector('tbody.farris-treetable-tbody');
        this.nodeExpanded.emit({ node: $event, tt: this.tt, tbody: tb });
    }
    onNodeExpanedAll() {
        this.nodeExpandedAll.emit();
    }

    onNodeCollapsedAll() {
        this.nodeCollapsedAll.emit();
    }

    /** 搜索节点后事件 */
    onSearched() {

    }
}
